Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
12 changes: 12 additions & 0 deletions .idea/GitlabLint.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .idea/excitingtools.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/ruff.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

237 changes: 107 additions & 130 deletions README.md

Large diffs are not rendered by default.

52 changes: 46 additions & 6 deletions excitingtools/__init__.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,54 @@
# Units
from excitingtools.constants.units import Unit

# User-level objects
from excitingtools.dataclasses import BandData, EigenValues

# old deprecated API
# Parsers returning to dicts
# Questionable whether one should expose this - required for test framework recursive comparisons
# Typically not the API one wants to expose to the user, as parsed dict keys are subject to change
from excitingtools.exciting_dict_parsers.parser_factory import parser_chooser
from excitingtools.exciting_dict_parsers.parser_factory import parse, parser_chooser

# Parsers returning to objects
from excitingtools.exciting_obj_parsers import *
# User-level objects
from excitingtools.dataclasses import *
from excitingtools.exciting_obj_parsers import parse_band_structure

# Input objects
from excitingtools.input import (
ExcitingEPHInput,
ExcitingGroundStateInput,
ExcitingGWInput,
ExcitingInputXML,
ExcitingMDInput,
ExcitingPhononsInput,
ExcitingPropertiesInput,
ExcitingRelaxInput,
ExcitingStructure,
ExcitingXSInput,
)

try:
from importlib import metadata
except ImportError:
import importlib_metadata as metadata

from pkg_resources import get_distribution
__version__ = metadata.version("excitingtools")

__version__ = get_distribution('excitingtools').version
__all__ = [
"Unit",
"BandData",
"EigenValues",
"parse",
"parser_chooser",
"parse_band_structure",
"ExcitingGroundStateInput",
"ExcitingXSInput",
"ExcitingPropertiesInput",
"ExcitingRelaxInput",
"ExcitingPhononsInput",
"ExcitingGWInput",
"ExcitingMDInput",
"ExcitingEPHInput",
"ExcitingInputXML",
"ExcitingStructure",
]
45 changes: 29 additions & 16 deletions excitingtools/constants/units.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
""" Units.
"""Units.

Physical constants, defined according to [CODATA 2018])(http://physics.nist.gov/constants)
One could also consider importing them from scipy
"""

import enum

bohr_to_angstrom = 0.529177210903
angstrom_to_bohr = 1.0 / bohr_to_angstrom
Hartree_to_eV = 27.211396641308


class Unit(enum.Enum):
"""
Expand All @@ -11,6 +19,7 @@ class Unit(enum.Enum):
This could be replaced with [PINT](https://pint.readthedocs.io/en/stable/), as used by NOMAD, however it's
currently not required. If/when we wish to do unit manipulation, it should be reconsidered.
"""

hartree = enum.auto()
inv_hartree = enum.auto()
ev = enum.auto()
Expand All @@ -25,25 +34,29 @@ class Unit(enum.Enum):
GK_max = enum.auto()
electron_rest_mass = enum.auto()
bohr_velocity_over_bohr_radius = enum.auto()
bohr_velocity = enum.auto()
force = enum.auto()
null = enum.auto()


# Map Unit enums to strings.
# Required because JSON cannot dump objects to file.
enum_to_string = {
Unit.hartree: 'Hartree',
Unit.inv_hartree: '1/Hartree',
Unit.ev: 'eV',
Unit.inv_ev: 'eV^-1',
Unit.kelvin: 'K',
Unit.bohr: 'Bohr',
Unit.bohr_pow_3: 'Bohr^3',
Unit.inv_bohr: 'Bohr^-1',
Unit.inv_bohr_pow_3: 'Bohr^-3',
Unit.au: 'a.u.',
Unit.degrees: 'degrees',
Unit.GK_max: 'GK_max',
Unit.electron_rest_mass: 'm_electron',
Unit.bohr_velocity_over_bohr_radius: 'v_Bohr/r_Bohr',
Unit.null: 'null'
Unit.hartree: "Hartree",
Unit.inv_hartree: "1/Hartree",
Unit.ev: "eV",
Unit.inv_ev: "eV^-1",
Unit.kelvin: "K",
Unit.bohr: "Bohr",
Unit.bohr_pow_3: "Bohr^3",
Unit.inv_bohr: "Bohr^-1",
Unit.inv_bohr_pow_3: "Bohr^-3",
Unit.au: "a.u.",
Unit.degrees: "degrees",
Unit.GK_max: "GK_max",
Unit.electron_rest_mass: "m_electron",
Unit.bohr_velocity_over_bohr_radius: "v_Bohr/r_Bohr",
Unit.bohr_velocity: "Bohr/t_Bohr",
Unit.force: "Hartree/Bohr",
Unit.null: "null",
}
4 changes: 3 additions & 1 deletion excitingtools/dataclasses/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
from excitingtools.dataclasses.band_structure import BandData
from excitingtools.dataclasses.eigenvalues import EigenValues
from excitingtools.dataclasses.eigenvalues import EigenValues

__all__ = ["BandData", "EigenValues"]
54 changes: 27 additions & 27 deletions excitingtools/dataclasses/band_structure.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
""" Band structure class.
"""
from typing import Tuple, List, Optional, Union
from excitingtools.eigenstates.eigenstates import get_k_point_index
"""Band structure class."""

from typing import List, Optional, Tuple, Union

import numpy as np

from excitingtools.eigenstates.eigenstates import get_k_point_index


class BandData:
ticks_and_labels = Tuple[np.ndarray, List[str]]
vertex_keys = ['distance', 'label', 'coord']

def __init__(self,
bands: np.ndarray,
k_points: np.ndarray,
e_fermi: float,
flattened_k_points: Optional[np.ndarray] = None,
vertices: Optional[List[dict]] = None):
""" Initialise BandData.
vertex_keys = ["distance", "label", "coord"]

def __init__(
self,
bands: np.ndarray,
k_points: np.ndarray,
e_fermi: float,
flattened_k_points: Optional[np.ndarray] = None,
vertices: Optional[List[dict]] = None,
):
"""Initialise BandData.

:param bands: Band energies with shape (n_k_points, n_bands).
:param: k_points: k-points at which the band energies have been computed.
Expand All @@ -34,7 +38,7 @@ def __init__(self,
self.i_vbm, self.i_cbm = self.get_band_edges()

def band_path(self) -> ticks_and_labels:
""" Get an array of points in the k-path that correspond to high symmetry points,
"""Get an array of points in the k-path that correspond to high symmetry points,
and a list of their labels.

vertices expected to have the form
Expand All @@ -47,8 +51,7 @@ def band_path(self) -> ticks_and_labels:
if self.vertices is None:
return np.empty(shape=1), []

assert list(self.vertices[0].keys()) == self.vertex_keys, \
f'Expect a vertex to have the keys {self.vertex_keys}'
assert list(self.vertices[0].keys()) == self.vertex_keys, f"Expect a vertex to have the keys {self.vertex_keys}"

vertices = [self.vertices[0]["distance"]]
labels = [self.vertices[0]["label"]]
Expand All @@ -60,22 +63,21 @@ def band_path(self) -> ticks_and_labels:
# Handle discontinuities in the band path
if np.isclose(vertex, vertices[-1]):
vertices.pop()
label = labels.pop() + ',' + label
label = labels.pop() + "," + label

vertices.append(vertex)
labels.append(label)

# Replace for plotting purposes
unicode_gamma = '\u0393'
for label in ['Gamma', 'gamma', 'G']:
unicode_gamma = "\u0393"
for label in ["Gamma", "gamma", "G"]:
labels = list(map(lambda x: x.replace(label, unicode_gamma), labels))

return np.asarray(vertices), labels

def get_k_point_index(self, k_point: Union[List[float], np.ndarray]) -> int:

if len(k_point) != 3:
raise TypeError('Expected type for k-point: list or NumPy array of length 3')
raise TypeError("Expected type for k-point: list or NumPy array of length 3")

return get_k_point_index(k_point, self.k_points, verbose=False)

Expand All @@ -96,18 +98,16 @@ def get_band_edges(self) -> Tuple[int, int]:
i_vbm = n_occupied - 1

if i_vbm + 1 >= self.n_bands:
raise ValueError(f'Fermi level {self.e_fermi} larger than highest band energy {np.amax(self.bands)}')
raise ValueError(f"Fermi level {self.e_fermi} larger than highest band energy {np.amax(self.bands)}")

return i_vbm, i_vbm + 1

def get_valence_band_maximum(self) -> float:
"""Get the value of the valence band maximum.
"""
"""Get the value of the valence band maximum."""
return np.amax(self.bands[:, self.i_vbm])

def get_conduction_band_minimum(self) -> float:
"""Get the value of the conduction band minimum.
"""
"""Get the value of the conduction band minimum."""
return np.amin(self.bands[:, self.i_cbm])

def get_fundamental_band_gap(self) -> float:
Expand All @@ -125,7 +125,7 @@ def get_fundamental_band_gap(self) -> float:
return self.bands[ik_c, self.i_cbm] - self.bands[ik_v, self.i_vbm]

def get_band_gap(self, k_valence, k_conduction):
""" Get the value of the band gap calculated between two given k-points.
"""Get the value of the band gap calculated between two given k-points.

:param k_valence: k-point for the valence band.
:param k_conduction: k-point for the valence band.
Expand Down
14 changes: 9 additions & 5 deletions excitingtools/dataclasses/data_structs.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,30 @@
""" Data Structures.
"""Data Structures.

Data structure is defined as a container for data.
Many of these classes could be @dataclass, however excitingtools
retains support for python 3.6.
"""


class PointIndex:
""" Container for (point, index) pair
"""
"""Container for (point, index) pair"""

def __init__(self, point, index: int):
self.point = point
self.index = index


class BandIndices:
"""Indices of valence band maximum and conduction band minimum"""

def __init__(self, VBM: int, CBm: int):
self.VBM = VBM
self.CBm = CBm


class NumberOfStates:
"""Number of states. Useful when indexing does not start at 0/1
"""
"""Number of states. Useful when indexing does not start at 0/1"""

def __init__(self, first_state: int, last_state: int):
self.first_state = first_state
self.last_state = last_state
Expand Down
2 changes: 1 addition & 1 deletion excitingtools/dataclasses/density_of_states.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import numpy as np

class DOS:

class DOS:
def __init__(self, energy: np.ndarray, dos: np.ndarray):
self.energy = energy
self.dos = dos
Loading